/* fpont 12/99 */
/* pont.net    */
/* udpClient.c */

/* Converted to echo client/server with select() (timeout option) */
/* 3/30/05 John Schultz */

#include <stdlib.h> /* for exit() */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h> /* memset() */
#include <sys/time.h> /* select() */
#include "consts.h"

#define REMOTE_SERVER_PORT 1500
#define MAX_MSG 100

/* BEGIN jcs 3/30/05 */

#define SOCKET_ERROR -1

int isReadable(int sd,int timeOut) { // milliseconds
  fd_set socketReadSet;
  FD_ZERO(&socketReadSet);
  FD_SET(sd,&socketReadSet);
  struct timeval tv;
  if (timeOut) {
    tv.tv_sec  = timeOut / 1000;
    tv.tv_usec = (timeOut % 1000) * 1000;
  } else {
    tv.tv_sec  = 0;
    tv.tv_usec = 0;
  } // if
  if (select(sd+1,&socketReadSet,0,0,&tv) == SOCKET_ERROR) {
    return 0;
  } // if
  return FD_ISSET(sd,&socketReadSet) != 0;
} /* isReadable */

/* END jcs 3/30/05 */

#define USER_NAME_ARG 1
#define CLIENT_PORT_ARG 2
#define SERVER_NAME_ARG 3
#define SERVER_PORT_ARG 4
#define MAX_MSG_LEN 512
#define TIMEOUT_CMD 500000
#define CMD_JOIN "join"
#define CMD_LEAVE "leave"
#define CMD_EXIT "exit"
#define CMD_SEND "send"
#define CMD_MYGROUPS "mygroups"
#define CMD_GROUPS "groups"
#define CMD_USERS "users"


struct sockaddr_in cliAddr, ctrlServAddr, msgServAddr;
char msg[MAX_MSG_LEN] = {0};
char* UserName;
int ClientPort;
char* ServerName;
int ServerPort;
int rc, ctrlSocket;

int recieveCmdResult(char* failMsg)
{
	int n,echoLen;
	if (!isReadable(ctrlSocket,TIMEOUT_CMD))
	{
	  printf("FAIL: No response from server.\n");
	  return 0;
	}
	echoLen = sizeof(msgServAddr);
	memset(msg,0x0,MAX_MSG);
	n = recvfrom(ctrlSocket, msg, MAX_MSG, 0,
		  (struct sockaddr *) &ctrlServAddr, &echoLen);
	if(n<0)
	{
	  printf("%s: cannot receive data \n",UserName);
	  return 0;
	}

	/* print received message */
	printf("%s: echo from %s:UDP%u : %s \n",
	  UserName,inet_ntoa(msgServAddr.sin_addr),
	  ntohs(msgServAddr.sin_port),msg);
	if (!strncmp(msg,RES_FAIL,strlen(RES_FAIL)))
	{
		printf("%s\n",failMsg);
		return 0;
	}
	else
	{
		printf("Success\n");
		return 1;
	}
}

void executeExit()
{
	char command[MAX_MSG_LEN] = {0};
	sprintf(command,"%s %s",UserName,CMD_EXIT);
	rc = sendto(ctrlSocket, command, strlen(command)+1, 0,
			(struct sockaddr *) &ctrlServAddr,
			sizeof(ctrlServAddr));

	recieveCmdResult("FAIL: exit failed.\n");

	printf("Bye!\n");
	exit(0);

}

void executeGroups()
{
	char command[MAX_MSG_LEN] = {0};
	sprintf(command,"%s %s",UserName,CMD_GROUPS);
	rc = sendto(ctrlSocket, command, strlen(command)+1, 0,
			(struct sockaddr *) &ctrlServAddr,
			sizeof(ctrlServAddr));

	recieveCmdResult("FAIL: exit failed.\n");

}

void executeJoin(char* group)
{
	char command[MAX_MSG_LEN] = {0};
	if (group == NULL)
	{
		printf("--bad usage! usage: join <group>\n");
		return;
	}
	sprintf(command,"%s %s %s",UserName,CMD_JOIN,group);
//	strncpy(msg,UserName,strlen(UserName));
//	strncat(msg," ",1);
//	strncat(msg,CMD_JOIN,strlen(CMD_JOIN));
//	strncat(msg," ",1);
//	strncat(msg,group,strlen(group));
	printf("group %s - Sending %s\n",group,command);
	rc = sendto(ctrlSocket, command, strlen(command)+1, 0,
			(struct sockaddr *) &ctrlServAddr,
			sizeof(ctrlServAddr));

	if(rc<0) {
	  printf("Cannot send Registration");
	  exit(1);
	}
//	memset(msg,0x0,MAX_MSG);

	recieveCmdResult("FAIL: max groups exceeded.\n");

}

void executeCommand(char* cmd)
{
	char * pch;
	printf("cmd = %s\n",cmd);
	pch = strtok (cmd," ");
	printf("pch = %s\n",pch);
	if (!strcmp(pch,CMD_JOIN))
	{
		executeJoin(strtok(NULL, " "));
	}
	else if (!strcmp(pch,CMD_LEAVE))
	{
//		executeLeave(strtok (NULL, " "));
	}
	else if (!strcmp(pch,CMD_EXIT))
	{
		executeExit();
	}
	else if (!strcmp(pch,CMD_SEND))
	{
		char* target = strtok (NULL, " ");
//		executeSend(target,pch + strlen(target) + 1);
	}
	else if (!strcmp(pch,CMD_MYGROUPS))
	{
//		executeMyGroups();
	}
	else if (!strcmp(pch,CMD_GROUPS))
	{
		executeGroups();
	}
	else if (!strcmp(pch,CMD_USERS))
	{
//		executeUsers(strtok (NULL, " "));
	}
	else
	{
		printf("Invalid command\n");
	}
}

int registerToServer()
{
	char port[6] = {0};
	sprintf(port,"%d",ClientPort);
	strncpy(msg,UserName,strlen(UserName));
	strncat(msg," ",1);
	strncat(msg,CMD_NEW,strlen(CMD_NEW));
	strncat(msg," ",1);
	strncat(msg,port,strlen(port));
	rc = sendto(ctrlSocket, msg, strlen(msg)+1, 0,
			(struct sockaddr *) &ctrlServAddr,
			sizeof(ctrlServAddr));

	if(rc<0) {
	  printf("Cannot send Registration");
	  exit(1);
	}
	memset(msg,0x0,MAX_MSG);
//  printf("ASDasd %s\n",ServerName);  exit(1);

	return recieveCmdResult("FAIL: can't register. max user exceeded or already registered.\n");
}

int main(int argc, char *argv[]) {

  int i, n, echoLen, flags, error, registerTimeOut;
  struct hostent *h;

  /* check command line args */
  if(argc!=5) {
    printf("Invalid arguments!\n");
    printf("usage : %s <user_name> <client_port> <server_name> <server_port>\n", argv[0]);
    exit(1);
  }

  UserName = argv[USER_NAME_ARG];
  ClientPort = atoi(argv[CLIENT_PORT_ARG]);
  ServerName = argv[SERVER_NAME_ARG];
  ServerPort = atoi(argv[SERVER_PORT_ARG]);


  /* get server IP address (no check if input is IP address or DNS name */
  h = gethostbyname(ServerName);
  if(h==NULL) {
    printf("Can't connect %s:%d!\n", ServerName, ServerPort);
    exit(1);
  }



  printf("Connecting to %s:%d (IP : %s)\n", ServerName, ServerPort, h->h_name,
	 inet_ntoa(*(struct in_addr *)h->h_addr_list[0]));


  ctrlServAddr.sin_family = h->h_addrtype;
  memcpy((char *) &ctrlServAddr.sin_addr.s_addr,
	 h->h_addr_list[0], h->h_length);
  ctrlServAddr.sin_port = htons(ServerPort);

  /* socket creation */
  ctrlSocket = socket(AF_INET,SOCK_DGRAM,0);
  if(ctrlSocket<0) {
    printf("Can't open socket\n");
    exit(1);
  }

  /* bind any port */
  cliAddr.sin_family = AF_INET;
  cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  cliAddr.sin_port = htons(0);

  rc = bind(ctrlSocket, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
  if(rc<0) {
    printf("Can't bind port\n");
    exit(1);
  }

/* BEGIN jcs 3/30/05 */

  flags = 0;

  registerTimeOut = 0; // ms

/* END jcs 3/30/05 */

  printf("Registering %s...\n",UserName);
  registerToServer();

  while (1)
  {
	  memset(msg,0x0,MAX_MSG_LEN);
	  if (scanf("%[^\n]%*c", msg) <= 0)
	  {
		  continue;
	  }

	  if (msg[0] == '!')
	  {
		  executeCommand(msg+1);
	  }
	  else
	  {
//		  sendMessage(msg);
	  }

  }
//
//  /* send data */
//  for(i=2;i<argc;i++) {
//    rc = sendto(ctrlSocket, argv[i], strlen(argv[i])+1, flags,
//		(struct sockaddr *) &ctrlServAddr,
//		sizeof(ctrlServAddr));
//
//    if(rc<0) {
//      printf("%s: cannot send data %d \n",argv[0],i-1);
//      close(ctrlSocket);
//      exit(1);
//    }
//
///* BEGIN jcs 3/30/05 */
//
//    /* init buffer */
//    memset(msg,0x0,MAX_MSG);
//
//    while (!isReadable(ctrlSocket,&error,timeOut)) printf(".");
//    printf("\n");
////
//  if (!isReadable(ctrlSocket,&error,registerTimeOut))
//  {
//	  printf("FAIL: No response from server.\n");
//	  exit(1);
//  }
//    /* receive echoed message */
//    echoLen = sizeof(msgServAddr);
//    n = recvfrom(ctrlSocket, msg, MAX_MSG, flags,
//      (struct sockaddr *) &msgServAddr, &echoLen);
//
//    if(n<0) {
//      printf("%s: cannot receive data \n",argv[0]);
////      continue;
//    }
//
//    /* print received message */
//    printf("%s: echo from %s:UDP%u : %s \n",
//      argv[0],inet_ntoa(msgServAddr.sin_addr),
//      ntohs(msgServAddr.sin_port),msg);
//
///* END jcs 3/30/05 */
//
//  }

  return 1;

}
